﻿using AJWPFAdmin.Core.Components.AJTable.ViewModels;
using AJWPFAdmin.Core.Enums;
using AJWPFAdmin.Core.ExtensionMethods;
using AJWPFAdmin.Core.HardwareSDKS.Models;
using AJWPFAdmin.Core.Logger;
using AJWPFAdmin.Core.Models;
using AJWPFAdmin.Core.Models.EF.Tables;
using AJWPFAdmin.Core.Utils;
using AJWPFAdmin.Services.AppointAPI.GoodsInfoQuery;
using AJWPFAdmin.Services.EF;
using AJWPFAdmin.Services.EF.TableExts;
using AJWPFAdmin.Services.Models;
using AngleSharp.Dom;
using Masuit.Tools.Reflection;
using Microsoft.Data.SqlClient;
using Microsoft.EntityFrameworkCore;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Prism.Ioc;
using Prism.Mvvm;
using Quartz.Impl.AdoJobStore.Common;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel.DataAnnotations;
using System.Data.Common;
using System.IO.Packaging;
using System.Linq;
using System.Net.Http;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using static AJWPFAdmin.Core.Models.DynamicFormItemDefineAttribute;
using static AJWPFAdmin.Services.AppointAPI.DefaultAppointAPI;

namespace AJWPFAdmin.Services.AppointAPI
{
    public class AppointAPIBase : BindableBase, IDisposable
    {

        public virtual string[] IgoreErrorKeyWords { get; set; }

        public event EventHandler<APILogsRaisedEventArgs> APILogsRaised;

        private SystemConfigDictionary _config;
        public SystemConfigDictionary Config
        {
            get => _config;
            set => _config = value;
        }

        protected object _customAPIConfig;

        public virtual string KeyDescription
        {
            get
            {
                return Config.Key.GetDescription();
            }
        }

        private bool _checked;
        /// <summary>
        /// 是否选中, 仅用于管理端接口配置
        /// </summary>
        public bool Checked
        {
            get
            {
                return _checked;
            }
            set
            {
                if (SetProperty(ref _checked, value))
                {
                    Config.BooleanValue = value;
                }
            }
        }

        private bool _autoUploadDataVerification;
        /// <summary>
        /// 是否自动上传核查数据, 各自第三方接口初始化完毕之后赋值
        /// </summary>
        public bool AutoUploadDataVerification
        {
            get
            {
                return _autoUploadDataVerification;
            }
            set
            {
                SetProperty(ref _autoUploadDataVerification, value);
            }
        }

        private ObservableCollection<DynamicFormItemSchema> _schemas;
        /// <summary>
        /// 动态表单列表,仅用于管理端接口配置
        /// </summary>
        public ObservableCollection<DynamicFormItemSchema> Schemas
        {
            get => _schemas;
            set => _schemas = value;
        }

        protected AJLog4NetLogger _logger;
        protected AJConfigService _configService;
        protected DbService db;
        protected ApplicationType _appType;
        protected CarIdentificationConfig _carIdentificationConfig;

        public AppointAPIBase(ApplicationType appType, SystemConfigDictionary cfg, IContainerProvider svcProvider)
        {
            _appType = appType;

            if (svcProvider != null)
            {
                _logger = svcProvider.Resolve<AJLog4NetLogger>();
                _configService = svcProvider.Resolve<AJConfigService>();
                db = DbService.GetDbContext(_configService);
                _carIdentificationConfig = CarIdentificationConfigExt.GetCarIdentificationConfig(db);
            }
            else
            {
                _carIdentificationConfig = new CarIdentificationConfig() { Type = CarIdentificationConfig.StoreType.本地 };
            }
            IgoreErrorKeyWords = new string[0];
            Config = cfg;

        }



        protected virtual void OnAPILogsRaised(
            PassagewayDirection? direction,
            string logs)
        {
            APILogsRaised?.Invoke(this, new APILogsRaisedEventArgs
            {
                Direction = direction,
                Logs = logs
            });
        }

        private List<DynamicFormItemSchema> ProcessSchemas(object customConfig, bool onlyVisible = true)
        {
            var props = customConfig.GetType().GetRuntimeProperties();
            var list = new List<DynamicFormItemSchema>();
            foreach (var prop in props)
            {
                var attr = prop.GetCustomAttribute<DynamicFormItemDefineAttribute>();
                if (attr != null)
                {
                    var item = new DynamicFormItemSchema
                    {
                        Label = attr.Label,
                        FormType = attr.FormType,
                        Field = prop.Name,
                        Value = prop.GetValue(customConfig),
                        Disable = attr.Disable,
                    };
                    if (item.FormType == VbenAdminFormType.Select && attr.OptionsHandler != null)
                    {
                        if (typeof(DynamicFormItemDefineAttribute.IOptionsHandle).IsAssignableFrom(attr.OptionsHandler))
                        {
                            var handler = (IOptionsHandle)Activator.CreateInstance(attr.OptionsHandler);

                            item.Options = new ObservableCollection<AJTableFormSchemaItemOptions>(handler.CreateOptions());

                            //item.SelectedOption = item.Options.FirstOrDefault(p => p.Value?.ToString() == item.Value?.ToString());
                        }
                    }
                    list.Add(item);
                }

            }
            return list;
        }

        /// <summary>
        /// 获取未审核通过车辆列表,ProcessResult.Data 必须是 AJTableFetchResult,AJTableFetchResult.Rows 必须是 List<NotAuditCarInfo>
        /// </summary>
        /// <param name="params"></param>
        /// <returns></returns>
        public virtual Task<ProcessResult> GetNotAuditCarListAsync(NotAuditCarListParams @params)
        {
            var result = new ProcessResult();
            result.SetSuccess(new AJTableFetchResult
            {
                Total = 0,
                HasNext = false,
            });
            return Task.FromResult(result);
        }

        /// <summary>
        /// 下载应急方案文件,ProcessResult.Data 必须是 AJTableFetchResult,AJTableFetchResult.Rows 必须是 List<EmergencyFileItem>
        /// </summary>
        /// <returns></returns>
        public virtual Task<ProcessResult> DownLoadEmergencyFileAsync()
        {
            var result = new ProcessResult();
            result.SetSuccess(new AJTableFetchResult
            {
                Total = 0,
                HasNext = false,
            });
            return Task.FromResult(result);
        }

        /// <summary>
        /// 获取报警信息列表
        /// </summary>
        /// <returns></returns>
        public virtual Task<ProcessResult> GetAlarmInfosAsync()
        {
            return Task.FromResult(ProcessResult.DefaultSuccess);
        }

        /// <summary>
        /// 录制视频,自行实现,返回值 ProcessResult.Data 是视频文件的物理路径
        /// </summary>
        /// <returns></returns>
        public virtual Task<ProcessResult> CaptureVideoAsync(CaptureVideoParams @params)
        {
            return Task.FromResult(ProcessResult.DefaultSuccess);
        }

        /// <summary>
        /// 查询排放超标车辆名单列表,ProcessResult.Data 必须是 AJTableFetchResult,AJTableFetchResult.Rows 必须是 List<ExcessiveEmissionsListItem>
        /// </summary>
        /// <param name="params"></param>
        /// <returns></returns>
        public virtual Task<ProcessResult> QueryExcessiveEmissionsListAsync(QueryIllegalVehicleParams @params)
        {
            var result = new ProcessResult();
            result.SetSuccess(new AJTableFetchResult
            {
                Total = 0,
                HasNext = false,
            });
            return Task.FromResult(result);
        }

        /// <summary>
        /// 企业排放超标信息核实结果上传
        /// </summary>
        /// <param name="params"></param>
        /// <returns></returns>
        public virtual Task<ProcessResult> CheckIllegalVehiclesAsync(CheckIllegalVehicleParams @params)
        {
            return Task.FromResult(ProcessResult.DefaultSuccess);
        }

        /// <summary>
        /// 查询违规通信车辆信息列表,ProcessResult.Data 必须是 AJTableFetchResult,AJTableFetchResult.Rows 必须是 List<ManageMeasureListItem>
        /// </summary>
        /// <param name="params"></param>
        /// <returns></returns>
        public virtual Task<ProcessResult> QueryIllegalVehicleListAsync(QueryIllegalVehicleParams @params)
        {
            var result = new ProcessResult();
            result.SetSuccess(new AJTableFetchResult
            {
                Total = 0,
                HasNext = false,
            });
            return Task.FromResult(result);
        }

        /// <summary>
        /// 查询企业管控措施列表,ProcessResult.Data 必须是 AJTableFetchResult,AJTableFetchResult.Rows 必须是 List<ManageMeasureListItem>
        /// </summary>
        /// <param name="params"></param>
        /// <returns></returns>
        public virtual Task<ProcessResult> QueryManageMeasureListAsync(QueryManageMeasureParams @params)
        {
            var result = new ProcessResult();
            result.SetSuccess(new AJTableFetchResult
            {
                Total = 0,
                HasNext = false,
            });
            return Task.FromResult(result);
        }

        /// <summary>
        /// 查询黑名单数据,ProcessResult.Data 必须是bool值,  true 表示黑名单, false 非黑名单
        /// </summary>
        /// <param name="params"></param>
        /// <returns></returns>
        public virtual Task<ProcessResult> QueryBlackListAsync(CarInfoParams @params)
        {
            var result = new ProcessResult();
            result.SetSuccess(false);
            return Task.FromResult(result);
        }

        /// <summary>
        /// 岗亭端每天定时上传前一天的核查数据
        /// </summary>
        /// <param name="params"></param>
        /// <returns></returns>
        public virtual Task<ProcessResult> UploadDataVerificationAsync(DataVerificationParams @params)
        {
            return Task.FromResult(ProcessResult.DefaultSuccess);
        }

        /// <summary>
        /// 管理端新增车辆信息后(本地数据保存至数据库之后),上传到第三方接口
        /// </summary>
        /// <returns></returns>
        public virtual Task<ProcessResult> UploadCarInfoAsync(CarInfoParams @params)
        {
            return Task.FromResult(ProcessResult.DefaultSuccess);
        }

        /// <summary>
        /// 管理端新增道闸信息后(本地数据保存至数据库之后),上传到第三方接口
        /// </summary>
        /// <returns></returns>
        public virtual Task<ProcessResult> UploadPssagewayAsync(PssagewayParams @params)
        {
            return Task.FromResult(ProcessResult.DefaultSuccess);
        }

        /// <summary>
        /// 管理端新增设备信息后(本地数据保存至数据库之后),上传到第三方接口
        /// </summary>
        /// <returns></returns>
        public virtual Task<ProcessResult> UploadDeviceInfoAsync(DeviceInfoParams @params)
        {
            return Task.FromResult(ProcessResult.DefaultSuccess);
        }

        /// <summary>
        /// 岗亭端新增台账记录(已保存到数据库),管理端新增台账记录后(本地数据保存至数据库之后),上传到第三方接口,ProcessResult.Attach 必须是 UploadShippingRecordResponse, 不管上传成功还是失败
        /// </summary>
        /// <returns></returns>
        public virtual Task<ProcessResult> UploadShippingRecordAsync(ShippingRecordParams @params)
        {
            var result = new ProcessResult();
            result.SetSuccess();
            result.Attach = new UploadShippingRecordResponse();
            return Task.FromResult(result);
        }

        public virtual DefaultAppointAPI.APIConfig GetGoodsInfoQueryTemplate(DbService db)
        {
            try
            {
                var defaultApiCfg = db.SystemConfigDictionaries.AsNoTracking()
                    .FirstOrDefault(p => p.Key == SystemConfigKey.APIDefault);

                var _apiCfg = CommonUtil.TryGetJSONObject<DefaultAppointAPI.APIConfig>(defaultApiCfg.StringValue)
                    ?? new DefaultAppointAPI.APIConfig();

                if (string.IsNullOrWhiteSpace(_apiCfg.QueryTemplate))
                {
                    _apiCfg.QueryTemplate = GoodsInfoQueryTemplate.无.ToString();
                }
                return _apiCfg;
            }
            catch (Exception)
            {
                return new APIConfig { QueryTemplate = GoodsInfoQueryTemplate.无.ToString() };
            }
        }

        /// <summary>
        /// 出/入厂,根据自定义的数据库配置获取货物信息,ProcessResult.Data 须是 AJWPFAdmin.Services.EF.TableExts.WeighingDataCacheExt 
        /// </summary>
        /// <param name="params"></param>
        /// <returns></returns>
        public virtual async Task<ProcessResult> GetGoodsInfoAsync(CarInfoParams @params)
        {
            var result = new ProcessResult();
            try
            {
                var _apiCfg = GetGoodsInfoQueryTemplate(db);

                var query = GoodsInfoQueryBase.Create(_configService, _apiCfg, _logger,
                    Enum.Parse<GoodsInfoQueryTemplate>(_apiCfg.QueryTemplate));

                WeighingDataCacheExt cache = null;

                var data = await query.QueryAsync(@params);
                if (data != null)
                {
                    cache = new WeighingDataCacheExt(data, _logger);
                    cache.QueryBase = query;
                }

                result.SetSuccess(cache);
            }
            catch (Exception e)
            {
                result.SetError($"查询出厂货物信息异常:{e.Message}", e);
            }
            return result;
        }

        /// <summary>
        /// 车牌识别后,从数据库获取了车辆数据,检测车辆数据信息是否完整
        /// </summary>
        /// <param name="params"></param>
        /// <returns></returns>
        public virtual Task<ProcessResult> CheckCarInfoAsync(CarInfoParams @params)
        {
            return Task.FromResult(ProcessResult.DefaultSuccess);
        }

        /// <summary>
        /// 车牌识别后,获取车辆信息,ProcessResult.Data 必须是 Car 实体,各个接口可以重写实现自己的处理逻辑
        /// </summary>
        /// <param name="params"></param>
        /// <returns></returns>
        public virtual async Task<ProcessResult> GetCarInfoNewAsync(CarInfoParams @params)
        {
            var result = new ProcessResult();
            try
            {
                using var db = DbService.GetDbContext(_configService);
                var vehicleRes = await GetEledgerVehicleInfoAsync(@params.CarInfo.CarNo, @params.Passageway.Direction);
                if (!vehicleRes.Success)
                {
                    result.SetError(vehicleRes.Message);
                    return result;
                }

                if (vehicleRes.Data == null)
                {
                    result.SetError($"{SystemConfigKey.APIDefault.GetDescription()} 未查询到车辆信息");
                    return result;
                }

                var eledgerCarInfo = vehicleRes.Data as Eledger_VehicleInfo ?? new Eledger_VehicleInfo();
                 
                 var carInfo = @params.CarInfo;
 
                 eledgerCarInfo.FillTo(ref carInfo);

                carInfo.IsOwnedByCompany = eledgerCarInfo.Reserve1;

                var usageDescription = eledgerCarInfo.UsageDescription;
                if (!string.IsNullOrWhiteSpace(usageDescription))
                {
                    var parentId = (long)SystemDictionaryExt.SystemDictionaryKey.使用性质;
                    var useDescDic = db.SystemDictionaries.AsNoTracking()
                        .FirstOrDefault(p => p.ParentId == parentId && p.Name == usageDescription);
                    if (useDescDic != null && @params.CarInfo.UsageDescCode != useDescDic.Code)
                    {
                        carInfo.UsageDescCode = useDescDic.Code;
                        carInfo.UsageDescription = useDescDic.Name;
                    }
                }

                var fuelTypeStr = eledgerCarInfo.FuelTypeName;

                if (!string.IsNullOrWhiteSpace(fuelTypeStr))
                {
                    var parentId = (long)SystemDictionaryExt.SystemDictionaryKey.燃料;
                    var fuleTypeDic = db.SystemDictionaries.AsNoTracking()
                        .FirstOrDefault(p => p.ParentId == parentId && p.Name == fuelTypeStr);
                    if (fuleTypeDic != null && @params.CarInfo.FuelTypeCode != fuleTypeDic.Code)
                    {
                        @params.CarInfo.FuelTypeCode = fuleTypeDic.Code;
                        @params.CarInfo.FuelTypeName = fuleTypeDic.Name;
                    }
                }

                var truckTypeStr = eledgerCarInfo.TruckTypeName;
                if (!string.IsNullOrWhiteSpace(truckTypeStr))
                {
                    var parentId = (long)SystemDictionaryExt.SystemDictionaryKey.货车;
                    var truckType = db.SystemDictionaries.AsNoTracking()
                        .FirstOrDefault(p => p.ParentId == parentId && p.Name == truckTypeStr);
                    if (truckType != null && @params.CarInfo.TruckTypeCode != truckType.Code)
                    {
                        @params.CarInfo.TruckTypeCode = truckType.Code;
                        @params.CarInfo.TruckTypeName = truckType.Name;
                    }
                }

                var goods = @params.Passageway.Direction == PassagewayDirection.进
                    ? carInfo.InGoodsName : carInfo.OutGoodsName;


                if (!string.IsNullOrWhiteSpace(goods))
                {
                    var weight = @params.Passageway.Direction == PassagewayDirection.进
                        ? carInfo.InGoodsVolume : carInfo.OutGoodsVolume;

                    @params.CarInfo.WeighingCacheData = new WeighingDataCache
                    {
                        SendOrReceiveFlag = @params.Passageway.Direction.ToString(),
                        GoodsName = goods,
                        GoodsWeight = weight
                    };
                    //todo-xq 默认接口查询货物名称填充
                    _logger.Error($"AppointAPIBase--GetCarInfoAsync--回执货物名称：{goods} --货物数量：{weight} ");
                }

                @params.CarInfo = carInfo;

                result.SetSuccess(@params.CarInfo);

            }
            catch (Exception e)
            {
                var keyDesc = SystemConfigKey.APIDefault.GetDescription();
                result.SetError($"{keyDesc} 获取车辆信息异常:{e.Message}");
                _logger.Error($"{keyDesc} 获取车辆信息异常", e);
            }
            return result;
        }

        /// <summary>
        /// 车牌识别后,获取车辆信息,ProcessResult.Data 必须是 Car 实体,各个接口可以重写实现自己的处理逻辑
        /// </summary>
        /// <param name="params"></param>
        /// <returns></returns>
        public virtual async Task<ProcessResult> GetCarInfoAsync(CarInfoParams @params)
        {
            var useNewEledger = _configService.Config["UseNewEledger"].TryGetBoolean();
            if (useNewEledger)
            {
                return await GetCarInfoNewAsync(@params);
            }
            var result = new ProcessResult();
            //// TODO: 本地调试, 直接返回假数据
            //@params.CarInfo.InGoodsName = "testa";
            //result.SetSuccess(@params.CarInfo);
            //return result;
            try
            {
                using var db = DbService.GetDbContext(_configService);
                var defaultApiCfg = db.SystemConfigDictionaries.AsNoTracking()
                    .FirstOrDefault(p => p.Key == SystemConfigKey.APIDefault);

                var _apiCfg = CommonUtil.TryGetJSONObject<DefaultAppointAPI.APIConfig>(defaultApiCfg.StringValue)
                    ?? new DefaultAppointAPI.APIConfig();

                using var _httpClient = CommonUtil.CreateCommonHttpClient();

                OnAPILogsRaised(@params.Passageway.Direction, $"获取车辆接口请求参数:\r\nplate:{@params.CarInfo.CarNo}\r\ncompany={_apiCfg.CompanyName}\r\n");

                var json = await _httpClient.GetStringAsync($"{_apiCfg.Url}?plate={@params.CarInfo.CarNo}&company={_apiCfg.CompanyName}");

                OnAPILogsRaised(@params.Passageway.Direction, $"获取车辆接口响应内容:\r\n{json}\r\n");

                var carRes = CommonUtil.TryGetJSONObject<DefaultAppointAPI.CarInfoAPIResponse>(json) ?? new DefaultAppointAPI.CarInfoAPIResponse
                {
                    success = false,
                    msg = "解析失败"
                };

                if (!carRes.success)
                {
                    result.SetError($"{SystemConfigKey.APIDefault.GetDescription()} 车辆信息接口失败:{carRes.msg}");
                    return result;
                }

                if (@params.CarInfo.EngineNo != carRes.data.engineNumber)
                {
                    @params.CarInfo.EngineNo = carRes.data.engineNumber;
                }

                if (Enum.TryParse<EmissionStandard>(carRes.data.emissionstage, out var emissionStd))
                {
                    if (@params.CarInfo.EmissionStandard != emissionStd)
                    {
                        @params.CarInfo.EmissionStandard = emissionStd;
                    }
                }

                if (@params.CarInfo.CarBrandModel != carRes.data.carModel)
                {
                    @params.CarInfo.CarBrandModel = carRes.data.carModel;
                }

                var useNNatureStr = carRes.data.operationLicenseImage;

                if (!string.IsNullOrWhiteSpace(useNNatureStr))
                {
                    var parentId = (long)SystemDictionaryExt.SystemDictionaryKey.使用性质;
                    var useDescDic = db.SystemDictionaries.AsNoTracking()
                        .FirstOrDefault(p => p.ParentId == parentId && p.Name == useNNatureStr);
                    if (useDescDic != null && @params.CarInfo.UsageDescCode != useDescDic.Code)
                    {
                        @params.CarInfo.UsageDescCode = useDescDic.Code;
                        @params.CarInfo.UsageDescription = useDescDic.Name;
                    }
                }

                var fuelTypeStr = carRes.data.useNNature;

                if (!string.IsNullOrWhiteSpace(fuelTypeStr))
                {
                    var parentId = (long)SystemDictionaryExt.SystemDictionaryKey.燃料;
                    var fuleTypeDic = db.SystemDictionaries.AsNoTracking()
                        .FirstOrDefault(p => p.ParentId == parentId && p.Name == fuelTypeStr);
                    if (fuleTypeDic != null && @params.CarInfo.FuelTypeCode != fuleTypeDic.Code)
                    {
                        @params.CarInfo.FuelTypeCode = fuleTypeDic.Code;
                        @params.CarInfo.FuelTypeName = fuleTypeDic.Name;
                    }
                }

                if (@params.CarInfo.TeamName != carRes.data.fleet)
                {
                    @params.CarInfo.TeamName = carRes.data.fleet;
                }

                var truckTypeStr = carRes.data.carType;

                if (!string.IsNullOrWhiteSpace(truckTypeStr))
                {
                    var parentId = (long)SystemDictionaryExt.SystemDictionaryKey.货车;
                    var truckType = db.SystemDictionaries.AsNoTracking()
                        .FirstOrDefault(p => p.ParentId == parentId && p.Name == truckTypeStr);
                    if (truckType != null && @params.CarInfo.TruckTypeCode != truckType.Code)
                    {
                        @params.CarInfo.TruckTypeCode = truckType.Code;
                        @params.CarInfo.TruckTypeName = truckType.Name;
                    }
                }

                if (@params.CarInfo.VIN != carRes.data.vin)
                {
                    @params.CarInfo.VIN = carRes.data.vin;
                }

                if (!string.IsNullOrWhiteSpace(carRes.data.registerTime))
                {
                    var regDate = carRes.data.registerTime.TryGetDate();
                    if (regDate != @params.CarInfo.RegDate)
                    {
                        @params.CarInfo.RegDate = regDate;
                    }
                }

                if (!string.IsNullOrWhiteSpace(carRes.data.driving_image))
                {
                    var img = CommonUtil
                    .AJSerializeObject(new string[] { carRes.data.driving_image });
                    if (@params.CarInfo.VehicleLicense != img)
                    {
                        @params.CarInfo.VehicleLicense = img;
                    }
                }

                if (@params.CarInfo.Owner != carRes.data.owner)
                {
                    @params.CarInfo.Owner = carRes.data.owner;
                }

                if (!string.IsNullOrWhiteSpace(carRes.data.list_image))
                {
                    var img = CommonUtil
                    .AJSerializeObject(new string[] { carRes.data.list_image });
                    if (@params.CarInfo.Attachments != img)
                    {
                        @params.CarInfo.Attachments = img;
                    }
                }

                if (!string.IsNullOrWhiteSpace(carRes.data.goods))
                {
                    var weight = carRes.data.goodsUnit.TryGetDecimal();

                    @params.CarInfo.WeighingCacheData = new WeighingDataCache
                    {
                        SendOrReceiveFlag = @params.Passageway.Direction.ToString(),
                        GoodsName = carRes.data.goods,
                        GoodsWeight = weight
                    };
                    //todo-xq 默认接口查询货物名称填充
                    _logger.Error($"AppointAPIBase--GetCarInfoAsync--回执货物名称：{carRes.data.goods} --货物数量：{weight} ");
                }

                result.SetSuccess(@params.CarInfo);

            }
            catch (Exception e)
            {
                var keyDesc = SystemConfigKey.APIDefault.GetDescription();
                result.SetError($"{keyDesc} 获取车辆信息异常:{e.Message}");
                _logger.Error($"{keyDesc} 获取车辆信息异常", e);
            }
            return result;
        }

        /// <summary>
        /// 企业信息(本地数据保存至数据库之后),上传到第三方接口
        /// </summary>
        /// <returns></returns>
        public virtual Task<ProcessResult> UploadComanyInfoAsync(string @params)
        {
            return Task.FromResult(ProcessResult.DefaultSuccess);
        }

        /// <summary>
        /// 出入口信息(本地数据保存至数据库之后),上传到第三方接口
        /// </summary>
        /// <returns></returns>
        public virtual Task<ProcessResult> UploadEntGateInfoAsync(WatchhouseInfoParams @params)
        {
            return Task.FromResult(ProcessResult.DefaultSuccess);
        }

        /// <summary>
        /// 排放超标信息(本地数据保存至数据库之后),上传到第三方接口
        /// </summary>
        /// <returns></returns>
        public virtual Task<ProcessResult> UploadEmiRiseRecordInfoAsync(EmiRiseRecordParams @params)
        {
            return Task.FromResult(ProcessResult.DefaultSuccess);
        }

        /// <summary>
        /// 各自接口转换自定义配置,API服务初始化的时候自动调用
        /// </summary>
        /// <param name="isReal">是否实际用API, 如果为false 则表示仅仅是管理端接口配置菜单那边初始化的,各接口根据此参数判断是否进行其他额外的真实转换操作</param>
        /// <returns></returns>
        public virtual Task ConvertToCustomConfig(bool isReal)
        {
            return Task.CompletedTask;
        }

        public virtual ObservableCollection<DynamicFormItemSchema> GetSchemas(bool onlyVisible = true)
        {
            if (Schemas == null || Schemas.Count == 0)
            {
                var list = ProcessSchemas(_customAPIConfig, onlyVisible);
                Schemas = new ObservableCollection<DynamicFormItemSchema>(list);
            }
            return Schemas;
        }

        /// <summary>
        /// 仅用于管理端更新各自配置信息
        /// </summary>
        public virtual void UpdateConfig(ref DbService db)
        {
            Config.BooleanValue = Checked;

            var props = _customAPIConfig.GetType().GetRuntimeProperties();

            var jobj = new JObject();

            foreach (var shcema in Schemas)
            {
                var prop = props.FirstOrDefault(p => p.Name == shcema.Field);
                if (prop == null)
                {
                    continue;
                }
                //prop.SetValue(_customAPIConfig, shcema.Value);
                jobj.Add(prop.Name, shcema.Value == null ? null : JToken.FromObject(shcema.Value));
            }

            var key = Config.Key;
            var dbCfg = db.SystemConfigDictionaries.FirstOrDefault(p => p.Key == key);
            if (dbCfg != null)
            {
                dbCfg.BooleanValue = Checked;
                dbCfg.StringValue = CommonUtil.AJSerializeObject(jobj);
                db.Entry(dbCfg).State = EntityState.Modified;
            }


        }

        public void Dispose()
        {

        }

        public virtual async Task<ProcessResult> GetEledgerVehicleInfoAsync(string plateNumber, PassagewayDirection? direction = null)
        {
            var result = new ProcessResult();
            try
            {
                using var db = DbService.GetDbContext(_configService);
                var defaultApiCfg = db.SystemConfigDictionaries
                    .FirstOrDefault(p => p.Key == SystemConfigKey.APIDefault);

                var _apiCfg = CommonUtil.TryGetJSONObject<DefaultAppointAPI.APIConfig>(defaultApiCfg.StringValue)
                    ?? new DefaultAppointAPI.APIConfig();

                using var _httpClient = CommonUtil.CreateCommonHttpClient();

                if (string.IsNullOrWhiteSpace(_apiCfg.AccessToken)
                    || DateTime.Now > _apiCfg.AccessTokenExpireDate)
                {
                    OnAPILogsRaised(direction, $"电子台账车辆预约接口正在登录:\r\nplate:{plateNumber}\r\nappid={_apiCfg.AppId}\r\nappsecret:{_apiCfg.AppSecret}");

                    var loginReqBody = new JObject
                    {
                        {"account", _apiCfg.AppId },
                        {"password", _apiCfg.AppSecret },
                    };

                    var loginReqContent = new StringContent(loginReqBody.ToString(), Encoding.UTF8, "application/json");

                    var loginRes = await _httpClient.PostAsync($"{_apiCfg.Url}/system/account/login?pid=480306", loginReqContent);

                    var rawResStr = await loginRes.Content.ReadAsStringAsync();

                    if (loginRes.StatusCode == System.Net.HttpStatusCode.OK)
                    {
                        var loginResult = CommonUtil.TryGetJSONObject<ProcessResult>(rawResStr, CommonUtil.CAMELCASEJSONSERIALIZERSETTINGS);

                        if (!loginResult.Success)
                        {
                            OnAPILogsRaised(direction, $"电子台账车辆预约接口登录失败:{loginResult.Message}");
                            return loginResult;
                        }

                        var obj = loginResult.Data as JObject;

                        _apiCfg.AccessToken = obj["token"].ToString();
                        _apiCfg.AccessTokenExpireDate = DateTime.Now.AddMinutes(29);

                        defaultApiCfg.StringValue = CommonUtil.AJSerializeObject(_apiCfg);
                        defaultApiCfg.UpdateDate = DateTime.Now;

                        db.Entry(defaultApiCfg).State = EntityState.Modified;
                        db.SaveChanges();
                    }
                    else
                    {
                        OnAPILogsRaised(direction, $"电子台账车辆预约接口登录请求失败:{loginRes.StatusCode}\r\n响应内容:{rawResStr}");
                        result.SetError($"{SystemConfigKey.APIDefault.GetDescription()} 电子台账车辆预约接口失败:{loginRes.StatusCode}");
                        return result;
                    }
                }

                _httpClient.DefaultRequestHeaders.TryAddWithoutValidation("Authorization", _apiCfg.AccessToken);

                OnAPILogsRaised(direction, $"电子台账车辆预约接口开始查询预约数据....");

                var json = await _httpClient.GetStringAsync($"{_apiCfg.Url}/eledger/system/vehicleInfo?plateNumber={plateNumber}");

                OnAPILogsRaised(direction, $"接口响应内容:\r\n{json}\r\n");

                var carRes = CommonUtil.TryGetJSONObject<ProcessResult>(json, CommonUtil.CAMELCASEJSONSERIALIZERSETTINGS) ?? new ProcessResult
                {
                    Success = false,
                    Message = "解析失败"
                };

                if (!carRes.Success)
                {
                    result.SetError($"{SystemConfigKey.APIDefault.GetDescription()} 车辆信息接口失败:{carRes.Message}");
                    return result;
                }

                if (carRes.Data == null)
                {
                    result.SetError($"{SystemConfigKey.APIDefault.GetDescription()} 未查询到车辆信息");
                    return result;
                }

                var eledgerCarInfo = CommonUtil.TryGetJSONObject<Eledger_VehicleInfo>(CommonUtil.AJSerializeObject(carRes.Data), CommonUtil.CAMELCASEJSONSERIALIZERSETTINGS)
                     ?? new Eledger_VehicleInfo();

                result.SetSuccess(eledgerCarInfo);
            }
            catch (Exception e)
            {
                var keyDesc = SystemConfigKey.APIDefault.GetDescription();
                result.SetError($"{keyDesc} 获取车辆信息异常:{e.Message}");
                _logger.Error($"{keyDesc} 获取车辆信息异常", e);
            }
            return result;
        }
    }

    public class APILogsRaisedEventArgs : EventArgs
    {
        public PassagewayDirection? Direction { get; set; }

        public string Logs { get; set; }
    }

    public enum DataOperationType
    {
        新增,
        更新,
        移除
    }

    public class APIParamsBase
    {
        /// <summary>
        /// 数据操作类型,管理端调用赋值
        /// </summary>
        public DataOperationType Operation { get; set; }
    }

    public class APIConfigBase
    {
        [DynamicFormItemDefine("数据核查自动上报", VbenAdminFormType.Switch)]
        public bool AutoUploadDataVerification { get; set; }
    }

    public class NotAuditCarListParams: APIParamsBase
    {
        public DateTime? Start { get; set; }

        public DateTime? End { get; set; }
    }

    public class CarInfoParams : APIParamsBase
    {
        public Car CarInfo { get; set; }

        public Passageway Passageway { get; set; }

        public Device Device { get; set; }

    }

    public class WatchhouseInfoParams : APIParamsBase
    {
        /// <summary>
        /// 出入口数据
        /// </summary>
        public Watchhouse Watchhouse { get; set; }
    }

    public class PssagewayParams : APIParamsBase
    {
        /// <summary>
        /// 道闸信息
        /// </summary>
        public Passageway Passageway { get; set; }
        /// <summary>
        /// 道闸关联的出入口数据
        /// </summary>
        public Watchhouse Watchhouse { get; set; }
    }

    public class DeviceInfoParams : PssagewayParams
    {
        public Device Device { get; set; }
    }

    public class EmiRiseRecordParams : APIParamsBase
    {
        /// <summary>
        /// 出入口数据
        /// </summary>
        public EmiRiseRecord EmiRiseRecord { get; set; }

        public Car CarInfo { get; set; }
    }

    public class ShippingRecordParams : APIParamsBase
    {
        public ShippingRecord Record { get; set; }
    }

    public class CaptureVideoParams
    {
        public ShippingRecord Record { get; set; }

        public DeviceInfo HIKDevice { get; set; }
    }

    public class UploadShippingRecordResponse
    {
        /// <summary>
        /// 过车记录上传次数
        /// </summary>
        public byte RecordNum { get; set; }

        /// <summary>
        /// 物资上传次数
        /// </summary>
        public byte GoodsNum { get; set; }

        /// <summary>
        /// 视频文件路径
        /// </summary>
        public string VideoFile { get; set; }
    }

    public class DataVerificationParams : BindableBase
    {
        private int _vechicleNum;
        /// <summary>
        /// 车辆数目,上报当日企业车辆台账总数
        /// </summary>
        public int VechicleNum
        {
            get => _vechicleNum;
            set
            {
                SetProperty(ref _vechicleNum, value);
            }
        }

        private int _inOutfactoryVechicleNum;
        /// <summary>
        /// 进出场车辆数目
        /// </summary>
        public int InOutFactoryVechicleNum
        {
            get => _inOutfactoryVechicleNum;
            set
            {
                SetProperty(ref _inOutfactoryVechicleNum, value);
            }
        }

        private int _inVechicleNum;
        /// <summary>
        /// 厂内车辆数目
        /// </summary>
        public int InVechicleNum
        {
            get => _inVechicleNum;
            set
            {
                SetProperty(ref _inVechicleNum, value);
            }
        }

        private int _nrVehicleNum;
        /// <summary>
        /// 非道路车辆数目
        /// </summary>
        public int NrVehicleNum
        {
            get => _nrVehicleNum;
            set
            {
                SetProperty(ref _nrVehicleNum, value);
            }
        }

        private int _vechiclePassingNum;
        /// <summary>
        /// 过车记录上报数
        /// </summary>
        public int VechiclePassingNum
        {
            get => _vechiclePassingNum;
            set
            {
                SetProperty(ref _vechiclePassingNum, value);
            }
        }

        private int _inVechiclePassingNum;
        /// <summary>
        /// 厂内车辆过车记录
        /// </summary>
        public int InVechiclePassingNum
        {
            get => _inVechiclePassingNum;
            set
            {
                SetProperty(ref _inVechiclePassingNum, value);
            }
        }

        private int _nrVechiclePassingNum;
        /// <summary>
        /// 非道路机械过车记录数
        /// </summary>
        public int NrVechiclePassingNum
        {
            get => _nrVechiclePassingNum;
            set
            {
                SetProperty(ref _nrVechiclePassingNum, value);
            }
        }

        private int _cargoLedgerNum;
        /// <summary>
        /// 货物台账数,上报当天货物台账记录总数
        /// </summary>
        public int CargoLedgerNum
        {
            get => _cargoLedgerNum;
            set
            {
                SetProperty(ref _cargoLedgerNum, value);
            }
        }

        private int _checkVechicleNum;
        /// <summary>
        /// 违规车辆核查数,上报当天违规车辆核查记录总数
        /// </summary>
        public int CheckVechicleNum
        {
            get => _checkVechicleNum;
            set
            {
                SetProperty(ref _checkVechicleNum, value);
            }
        }

        private DateTime _recordDate;
        /// <summary>
        /// 记录时间,上报数据的日期，如2024年3月18日00点上报的2024年3月17日数据，则记录2024-03-17
        /// </summary>
        public DateTime RecordDate
        {
            get => _recordDate;
            set
            {
                SetProperty(ref _recordDate, value);
            }
        }

        private DateTime _recordEndDate;
        /// <summary>
        /// 记录截至时间
        /// </summary>
        public DateTime RecordEndDate
        {
            get => _recordEndDate;
            set
            {
                SetProperty(ref _recordEndDate, value);
            }
        }


        public static async Task<DataVerificationParams> ComputeAsync(DbService db, DateTime? date = null)
        {
            var computeDate = date.HasValue ? date.GetValueOrDefault() : DateTime.Today.AddDays(-1);
            var result = new DataVerificationParams
            {
                RecordDate = computeDate,
                RecordEndDate = computeDate.Date.AddHours(23).AddMinutes(59).AddSeconds(59)
            };

            var end = result.RecordEndDate;

            var recordSource = await db.ShippingRecords
                .Where(p => p.Synchronized && p.ShipEndDate >= computeDate && p.ShipEndDate <= end)
                .Select(p => new
                {
                    p.TypeId,
                    p.CarNo,
                    p.ShipEndDate,
                    p.RecordNum,
                    p.GoodsNum
                }).ToListAsync();

            result.VechicleNum = recordSource.GroupBy(p => p.CarNo).Select(p => p.Count()).Sum();

            result.InOutFactoryVechicleNum = recordSource.Where(p => p.TypeId == (long)CarTypeEnum.进出厂车)
               .GroupBy(p => p.CarNo).Select(p => p.Count()).Sum();

            result.InVechicleNum = recordSource.Where(p => p.TypeId == (long)CarTypeEnum.厂内运输车)
                .GroupBy(p => p.CarNo).Select(p => p.Count()).Sum();

            result.NrVehicleNum = recordSource.Where(p => p.TypeId == (long)CarTypeEnum.非道路移动机械)
                .GroupBy(p => p.CarNo).Select(p => p.Count()).Sum();

            result.VechiclePassingNum = recordSource.Sum(p => p.RecordNum);

            result.InVechiclePassingNum = recordSource.Where(p => p.TypeId == (long)CarTypeEnum.厂内运输车).Sum(p => p.RecordNum);

            result.NrVechiclePassingNum = recordSource.Where(p => p.TypeId == (long)CarTypeEnum.非道路移动机械).Sum(p => p.RecordNum);

            result.CargoLedgerNum = recordSource.Sum(p => p.GoodsNum);

            result.CheckVechicleNum = 0;

            return result;
        }
    }

    public class QueryManageMeasureParams
    {

    }

    public class ManageMeasureListItem
    {
        /// <summary>
        /// 预警响应开始时间
        /// </summary>
        [Display(Name = "预警响应开始时间")]
        public string WarnStartTime { get; set; }

        /// <summary>
        /// 预警响应结束时间
        /// </summary>
        [Display(Name = "预警响应结束时间")]
        public string WarnEndTime { get; set; }

        /// <summary>
        /// 预警级别
        /// </summary>
        [Display(Name = "预警级别")]
        public ManageMeasureWarnLevel WarnLevel { get; set; }

        /// <summary>
        /// 响应级别
        /// </summary>
        [Display(Name = "响应级别")]
        public ManageMeasureResponseLevel ResponseLevel { get; set; }

        /// <summary>
        /// 管控措施
        /// </summary>
        [Display(Name = "管控措施")]
        public string ControlMeasure { get; set; }
    }

    public class CheckIllegalVehicleParams
    {
        /// <summary>
        /// 车牌号
        /// </summary>
        public string PlateNo { get; set; }

        /// <summary>
        /// 车牌颜色
        /// </summary>
        public CarPlateColor PlateColor { get; set; }

        /// <summary>
        /// VIN
        /// </summary>
        public string VIN { get; set; }

        /// <summary>
        /// 核实结果 0—超标；1—不超标
        /// </summary>
        public int CheckResult { get; set; }

        ///// <summary>
        ///// 说明材料图片
        ///// </summary>
        //public string checkImage { get; set; }

        /// <summary>
        /// 车队名,自有、个人或运输
        /// </summary>
        public string FleetName { get; set; }
    }

    public class QueryIllegalVehicleParams
    {
        public CarPlateColor? Color { get; set; }

        public string CarNo { get; set; }

        public DateTime? StartDate { get; set; }

        public DateTime? EndDate { get; set; }

        public int Page { get; set; }

        public int Limit { get; set; }
    }

    public class IllegalVehicleListItem
    {
        /// <summary>
        /// 车牌号码
        /// </summary>
        [Display(Name = "车牌号码")]
        public string CarNo { get; set; }

        /// <summary>
        /// 号牌颜色
        /// </summary>
        [Display(Name = "号牌颜色")]
        public CarPlateColor Color { get; set; }

        /// <summary>
        /// 车辆识别代码(VIN)
        /// </summary>
        [Display(Name = "车辆识别代码(VIN)")]
        public string VIN { get; set; }

        /// <summary>
        /// 进厂时间
        /// </summary>
        [Display(Name = "进厂时间)")]
        public string EntryTime { get; set; }

        /// <summary>
        /// 出厂时间
        /// </summary>
        [Display(Name = "出厂时间)")]
        public string DeliveryTime { get; set; }

        /// <summary>
        /// 违规通行原因
        /// </summary>
        [Display(Name = "违规通行原因)")]
        public string Reason { get; set; }

        /// <summary>
        /// 其他说明
        /// </summary>
        [Display(Name = "其他说明)")]
        public string Remark { get; set; }
    }

    public class ExcessiveEmissionsListItem
    {
        /// <summary>
        /// 车牌号码
        /// </summary>
        [Display(Name = "车牌号码")]
        public string CarNo { get; set; }

        /// <summary>
        /// 号牌颜色
        /// </summary>
        [Display(Name = "号牌颜色")]
        public CarPlateColor Color { get; set; }

        /// <summary>
        /// 车辆识别代码(VIN)
        /// </summary>
        [Display(Name = "车辆识别代码(VIN)")]
        public string VIN { get; set; }

        /// <summary>
        /// 燃料类型
        /// </summary>
        [Display(Name = "燃料类型)")]
        public string FuelType { get; set; }

        /// <summary>
        /// 排放标准
        /// </summary>
        [Display(Name = "排放标准)")]
        public EmissionStandard EmissionStandard { get; set; }

        /// <summary>
        /// 超标原因
        /// </summary>
        [Display(Name = "超标原因)")]
        public ExcessiveEmissionsReason DeliveryReason { get; set; }

        /// <summary>
        /// 是否解除, true 解除, false 未解除
        /// </summary>
        [Display(Name = "是否解除)")]
        public bool State { get; set; }

        /// <summary>
        /// 下发时间
        /// </summary>
        [Display(Name = "下发时间)")]
        public string DeliveryTime { get; set; }

        /// <summary>
        /// 解除时间
        /// </summary>
        [Display(Name = "解除时间)")]
        public string ReleaseTime { get; set; }

    }

    public enum ExcessiveEmissionsReason : byte
    {
        环保定期检验 = 1,
        远程监控,
        路检路查,
        入户检查,
        尾气遥感监测,
        黑烟举报,
        其他
    }

    public enum ManageMeasureWarnLevel : byte
    {
        黄色 = 1,
        橙色,
        红色,
        日常管控,
        自定义管控
    }

    public enum ManageMeasureResponseLevel : byte
    {
        Ⅰ级 = 1,
        Ⅱ级,
        Ⅲ级
    }

    public class EmergencyFileItem
    {
        public string Name { get; set; }

        public string Url { get; set; }
    }

    public class NotAuditCarInfo
    {
        public string PlateNumber { get; set; }

        public string CarType { get; set; }

        public string Status { get; set; }

        public string Remark { get; set; }
    }

    public enum ApplicationType : byte
    {
        岗亭端,
        管理端
    }
}
